#pragma once 

#include <iostream>
#include <unordered_map>
#include <string>
#include <sys/epoll.h>
#include <unistd.h>

#define SIZE 1024
#define NUM  128

// 一般处理IO的时候，我们只有三种接口需要处理
// 1、处理读取 2、处理写入 3、处理异常

class Event;
class Reactor;
typedef int(*callback_t)(Event *ev); // 函数指针

// 需要让epoll管理的基本结点
class Event{
public:
    int sock;               // 对应的文件描述符
    std::string inbuffer;   // sock对应的输入缓冲区
    std::string outbuffer;  // sock对应的输出缓冲区

    // sock设置回调
    callback_t recver;
    callback_t sender;
    callback_t errorer;

    // 试着Event回指Reactor的指针
    Reactor *R;

public:
    Event(){
        sock = -1;
        recver = nullptr;
        sender = nullptr;
        errorer = nullptr;
        R = nullptr;
    }
    void RegisterCallback(callback_t _recver, callback_t _sender, callback_t _errorer){
        recver = _recver;
        sender = _sender;
        errorer = _errorer;
    } 

};

// 不需要关心任何sock类型(listen, 读, 写)
// 如何使用该类，对Event进行管理
class Reactor{ //反应堆模式
public:
    Reactor() :epfd(-1){}
    ~Reactor(){}
    void InitReactor();
    bool InsertEvent(Event *evp, uint32_t concernedevents);
    void DeleteEvent(Event *evp);
    bool EnableReadWriter(int sock, bool enable_read, bool enable_write);
    void Dispatcher(int timeout);    //就绪事件的派发器逻辑
    bool IsSockOk(int sock);
private:
    int epfd;
    std::unordered_map<int, Event*> events; //Epoll类管理的所有Event对象集合
};

void Reactor::InitReactor(){
    epfd = epoll_create(SIZE);
    if (epfd < 0){
        std::cerr << "epoll_create error" << std::endl;
        exit(2);
    }
    std::cout << "Init Reactor success" << std::endl;
}

bool Reactor::InsertEvent(Event* evp, uint32_t concerned_events){
    // 1.将ev中的sock插入到epoll中
    // 2.将ev本身插入到unordered_map中
    struct epoll_event ev;
    ev.events = concerned_events;
    ev.data.fd = evp->sock;
    // 1、将sock插入到epoll中
    if (epoll_ctl(epfd, EPOLL_CTL_ADD, evp->sock, &ev) < 0){
        std::cerr << "epoll_ctl add event failed" << std::endl;
        return false;
    }
    events.insert({evp->sock, evp});
}
void Reactor::DeleteEvent(Event *evp){
    int sock = evp->sock;
    auto iter = events.find(sock);
    if (iter != events.end()){
        events.erase(iter);             // 特定ev从unordered_map中移除
        epoll_ctl(epfd, EPOLL_CTL_DEL, sock, nullptr); // 将sock从epoll管理的sock中移除
        close(sock);                    // 关闭文件描述符
        delete evp;                     // 删除Event结点
    }
}

// 使能够读写
bool Reactor::EnableReadWriter(int sock, bool enable_read, bool enable_write){
    struct epoll_event ev;
    ev.events = EPOLLET | (enable_read ? EPOLLIN : 0) | (enable_write ? EPOLLOUT : 0);
    ev.data.fd = sock;

    if (epoll_ctl(epfd, EPOLL_CTL_MOD, sock, &ev) < 0){
        std::cerr << "epoll_ctl mod event failed" << std::endl;
        return false;
    }
    return true;
}

bool Reactor::IsSockOk(int sock){
    auto iter = events.find(sock);
    return iter != events.end();
}

void Reactor::Dispatcher(int timeout){
    struct epoll_event revs[NUM];
    int n = epoll_wait(epfd, revs, NUM, timeout);
    for (int i = 0; i < n; i++){
        int sock = revs[i].data.fd;
        uint32_t revents = revs[i].events;
        // 差错处理:将所有的问题全部转化成让IO函数去解决
        if (revents & EPOLLERR) revents |= (EPOLLIN | EPOLLOUT); // 对应的文件描述符出现错误
        if (revents & EPOLLHUP) revents |= (EPOLLIN | EPOLLOUT); // 对应的文件描述符被挂断
        // 读事件就绪
        if (revents & EPOLLIN){
            if (IsSockOk(sock) && events[sock]->recver) events[sock]->recver(events[sock]); //recver回调函数被设置过，则调用进行读取
        }
        if (revents & EPOLLOUT){
            if (IsSockOk(sock) && events[sock]->sender) events[sock]->sender(events[sock]); //sender回调函数被设置过，则调用进行发送
        }
    }
} 